﻿using Abp.Linq.Expressions;
using Common.Enums;
using Entity.Models.dto;
using Entity.Models.Entities;
using Entity.Models.vo;
using IBLL;
using IDAL;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using utils.enums;
using utils.Enums;
using utils.EX;
using Utils;

namespace BLL
{
    /// <summary>
    /// 耗材BLL层
    /// </summary>
    public class ConsumableInfoBLL : IConsumableInfoBLL
    {
        IConsumableInfoDAL _consumableInfoDal;

        /// <summary>
        /// 数据库上下文
        /// </summary>
        RepositorySysContext _dbsysContext;

        /// <summary>
        /// 用户接口
        /// </summary>
        IUserDAL _userDAL;

        /// <summary>
        /// 耗材类别DAL接口
        /// </summary>
        ICategoryDAL _categoryDAL;

        /// <summary>
        /// 耗材记录DAL接口
        /// </summary>
        IConsumableRecordDAL _consumableRecordDAL;

        public ConsumableInfoBLL(IConsumableInfoDAL consumableInfo, IUserDAL userDAL, ICategoryDAL categoryDAL, IConsumableRecordDAL consumableRecordDAL, RepositorySysContext dbsysContext)
        {
            _consumableInfoDal = consumableInfo;
            _userDAL = userDAL;
            _categoryDAL = categoryDAL;
            _consumableRecordDAL = consumableRecordDAL;
            _dbsysContext = dbsysContext;
        }

        /// <summary>
        /// 耗材数据列表、搜索
        /// </summary>
        /// <param name="ConsumableInfoName">耗材名称</param>
        /// <param name="page">页数</param>
        /// <param name="limit">数据条数</param>
        /// <returns></returns>
        public List<ConsumableInfoDTO> getconsumableInfoList(string ConsumableInfoName, string page, string limit, out int cont)
        {
            //连表
            var datas = from d in _consumableInfoDal.getEntitys().Where(i => i.IsDelete != true)
                        join u in _categoryDAL.getEntitys()
                        on d.CategoryId equals u.Id
                        into Temedu
                        from uu in Temedu.DefaultIfEmpty()
                            //select new ConsumableInfoDTO(d, uu);
                        select new ConsumableInfoDTO
                        {
                            Id = d.Id,
                            _createTimes = d.CreateTime,
                            _description = d.Description,
                            _consumableName = d.ConsumableName,
                            _num = d.Num,
                            _unit = d.Unit,
                            _money = d.Money,
                            _warningNum = d.WarningNum,
                            _categoryId = uu.CategoryName
                        };
            //搜索
            if (!string.IsNullOrEmpty(ConsumableInfoName))
            {
                datas = datas.Where(i => i._consumableName.Contains(ConsumableInfoName));
            }
            //分页
            var pageconsumableInfo = datas.OrderByDescending(d => d._createTimes).Skip((int.Parse(page) - 1) * int.Parse(limit)).Take(int.Parse(limit)).ToList();
            cont = datas.Count();

            List<ConsumableInfoDTO> consumableInfoDTOs = new List<ConsumableInfoDTO>();
            foreach (var item in pageconsumableInfo)
            {
                consumableInfoDTOs.Add(new ConsumableInfoDTO(item));
            }
            return consumableInfoDTOs;
        }

        /// <summary>
        /// 添加耗材
        /// </summary>
        /// <param name="consumableInfo"></param>
        /// <returns></returns>。
        public bool AddConsumableInfo(ConsumableInfo consumableInfo)
        {
            consumableInfo.Id = Guid.NewGuid().ToString();
            consumableInfo.CreateTime = DateTime.Now;
            //根据账号查询用户信息
            ConsumableInfo byconsumableInfoInfo = _consumableInfoDal.getEntitys().FirstOrDefault(d => d.IsDelete != true && d.ConsumableName == consumableInfo.ConsumableName);
            if (byconsumableInfoInfo == null)
            {
                //保存
                if (_consumableInfoDal.AddEntity(consumableInfo) < 0)
                {
                    throw new MyException(((int)UserEnums.USER_STATE.LOSE), Enums.getDescribe(UserEnums.USER_STATE.LOSE));
                }
            }
            else
            {
                throw new MyException(((int)ConsumableInfoEnums.STATE.ALREADY), Enums.getDescribe(ConsumableInfoEnums.STATE.ALREADY));
            }
            return true;
        }

        /// <summary>
        /// 删除耗材
        /// </summary>
        /// <param name="consumableInfoId">耗材id</param>
        /// <returns></returns>
        public bool DalateConsumableInfo(string consumableInfoId)
        {
            //删除
            if (_consumableInfoDal.SoftDalateEntity(consumableInfoId) < 0)
            {
                throw new MyException(((int)UserEnums.USER_STATE.DATATE_LOSE), Enums.getDescribe(UserEnums.USER_STATE.DATATE_LOSE));
            }
            return true;
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="consumableInfoIds"></param>
        /// <returns></returns>
        public bool DalateConsumableInfoList(List<String> consumableInfoIds)
        {
            if (consumableInfoIds.Count < 1)
            {
                throw new MyException(((int)UserEnums.USER_STATE.UPDATE_LIST), Enums.getDescribe(UserEnums.USER_STATE.UPDATE_LIST));
            }
            foreach (var item in consumableInfoIds)
            {
                DalateConsumableInfo(item);
            }
            return true;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="consumableInfo"></param>
        /// <returns></returns>
        public bool UpdataConsumableInfo(ConsumableInfo consumableInfo)
        {
            var consumableInfos = _consumableInfoDal.getByEntityId(consumableInfo.Id);
            consumableInfos.ConsumableName = consumableInfo.ConsumableName;
            consumableInfos.CategoryId = consumableInfo.CategoryId;
            consumableInfos.Description = consumableInfo.Description;
            consumableInfos.Specification = consumableInfo.Specification;
            consumableInfos.Unit = consumableInfo.Unit;
            consumableInfos.Money = consumableInfo.Money;
            consumableInfos.WarningNum = consumableInfo.WarningNum;
            if (_consumableInfoDal.UpdataEntity(consumableInfos) < 0)
            {
                throw new MyException(((int)UserEnums.USER_STATE.UPDATE_LOSE), Enums.getDescribe(UserEnums.USER_STATE.UPDATE_LOSE));
            }
            return true;
        }


        /// <summary>
        /// 根据耗材id搜索
        /// </summary>
        /// <param name="consumableInfoid"></param>
        /// <returns></returns>
        public ConsumableInfo getByConsumableInfo(string consumableInfoid)
        {
            return _consumableInfoDal.getByEntityId(consumableInfoid);
        }


        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="stream">文件流</param>
        /// <param name="extension">文件后缀</param>
        /// <param name="userId">用户id</param>
        /// <returns></returns>
        public bool Upload(Stream stream, string extension, string userId)
        {
            IWorkbook wk = null;
            if (extension.Equals(".xls"))
            {
                //把xls文件中的数据写入wk中
                wk = new HSSFWorkbook(stream);
            }
            else
            {
                //把xlsx文件中的数据写入wk中
                wk = new XSSFWorkbook(stream);
            }
            stream.Close();

            //读取当前表数据
            ISheet sheet = wk.GetSheetAt(0);

            //事务
            using (var Transaction = _dbsysContext.Database.BeginTransaction())
            {
                for (int i = 0; i < sheet.LastRowNum; i++)
                {
                    IRow row = sheet.GetRow(i + 1);  //读取当前行数据
                    var ConsumableName = row.GetCell(0).ToString(); //读取耗材名称
                    var Cell1 = row.GetCell(1).ToString(); //读取预计购买数据
                    int Nums = 0; //实际购买数量
                    int.TryParse(Cell1, out Nums);
                    var Cell2 = row.GetCell(2).ToString(); //读取实际购买数量
                    var Money = row.GetCell(3).ToString(); //读取价格
                    var sku = row.GetCell(4).ToString(); //读取规格

                    ConsumableInfo consumableInfo = _consumableInfoDal.getEntitys().FirstOrDefault(c => c.ConsumableName.EndsWith(ConsumableName) && c.Specification.EndsWith(sku));
                    //判断耗材和耗材规格是否匹配
                    if (consumableInfo != null)
                    {
                        //添加耗材记录
                        if (_consumableRecordDAL.AddEntity(new ConsumableRecord(consumableInfo.Id, userId, Nums, 1)) < 1)
                        {
                            Transaction.Rollback();//回滚
                            throw new MyException(701, $"第 {i + 1} 行耗材：{ConsumableName} 添加失败，请检查名称或规格是否正确");
                        }
                        //更新耗材库存 
                        consumableInfo.Num += Nums;
                        if (_consumableInfoDal.UpdataEntity(consumableInfo) < 1)
                        {
                            Transaction.Rollback();//回滚
                            throw new MyException(703, $"更新耗材库存失败");
                        }
                    }
                    else
                    {
                        Transaction.Rollback();//回滚
                        throw new MyException(702, $"第 {i + 1} 行“{ConsumableName}”名称或“{sku}”规格有误");
                    }
                }

                //提交事务
                Transaction.Commit();
                return true;
            }

        }


        /// <summary>
        /// 文件下载
        /// </summary>
        /// <returns>文件流</returns>
        public Stream DownloadFile()
        {
            //连表
            var datas = (from cc in _consumableRecordDAL.getEntitys()
                         join c in _consumableInfoDal.getEntitys().Where(c => c.IsDelete != true)
                         on cc.ConsumableId equals c.Id
                         into tmpecb
                         from cb in tmpecb.DefaultIfEmpty()

                         join u in _userDAL.getUserShowDAL().Where(u => u.IsDelete != true)
                         on cc.Creator equals u.Id
                         into tmpeuu
                         from uu in tmpeuu.DefaultIfEmpty()
                         select new
                         {
                             cb.ConsumableName,
                             cb.Specification,
                             cc.Type,
                             cc.Num,
                             cc.CreateTime,
                             uu.UserName
                         }).ToList();

            //获取项目目录
            string path = Directory.GetCurrentDirectory();
            string filePath = Path.Combine(path, "Download.xlsx");

            IWorkbook wk = null;
            //获取文件拓展名
            string extension = Path.GetExtension(filePath);

            FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
            if (extension.Equals(".xls"))  //2003
            {
                //把xls文件中的数据写入wk中
                wk = new HSSFWorkbook();
            }
            else
            {
                //把xlsx文件中的数据写入wk中  2007
                wk = new XSSFWorkbook();
            }

            //创建sheet表
            ISheet sheet = wk.CreateSheet("sheet1");

            //创建第一行
            IRow row = sheet.CreateRow(0);

            //创建单元格
            ICell cell = row.CreateCell(0);
            //写内容到单元格中
            cell.SetCellValue("耗材名称");

            //创建单元格
            ICell cell1 = row.CreateCell(1);
            //写内容到单元格中
            cell1.SetCellValue("规格");

            //创建单元格
            ICell cell2 = row.CreateCell(2);
            //写内容到单元格中
            cell2.SetCellValue("类型");

            //创建单元格
            ICell cell3 = row.CreateCell(3);
            //写内容到单元格中
            cell3.SetCellValue("数量");

            //创建单元格
            ICell cell4 = row.CreateCell(4);
            //写内容到单元格中
            cell4.SetCellValue("购买时间");

            //创建单元格
            ICell cell5 = row.CreateCell(5);
            //写内容到单元格中
            cell5.SetCellValue("采购人");

            for (int i = 0; i < datas.Count; i++)
            {
                var data = datas[i];
                //创建第一行
                IRow rows = sheet.CreateRow(i+1);

                //创建单元格
                ICell cells = rows.CreateCell(0);
                //写内容到单元格中
                cells.SetCellValue(data.ConsumableName);

                //创建单元格
                ICell cell1s = rows.CreateCell(1);
                //写内容到单元格中
                cell1s.SetCellValue(data.Specification);

                //创建单元格
                ICell cells2 = rows.CreateCell(2);
                //写内容到单元格中
                cells2.SetCellValue(data.Type.ToString());

                //创建单元格
                ICell cell3s = rows.CreateCell(3);
                //写内容到单元格中
                cell3s.SetCellValue(data.Num);

                //创建单元格
                ICell cell4s = rows.CreateCell(4);
                //写内容到单元格中
                cell4s.SetCellValue(data.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"));

                //创建单元格
                ICell cell5s = rows.CreateCell(5);
                //写内容到单元格中
                cell5s.SetCellValue(data.UserName);
            }

            //把excel对象的内容写到文件流中
            wk.Write(fs);

            //返回一个文件流
            FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            return fileStream;
        }

        /// <summary>
        /// 工作流管理物品下拉框
        /// </summary>
        /// <returns></returns>
        public List<TransferVo> getOutGoodsSelect()
        {
            return _consumableInfoDal.getEntitys().Where(c => c.IsDelete != true).Select(c => new TransferVo(c)).ToList();
        }
    }
}
